<?php

namespace app\miniweb\controller;

use app\common\cachemodel\MiniAppUser;
use app\common\lib\exception\ApiException;
use app\common\model\User;
use think\Controller;

class Auth extends Controller
{
    /**
     * 登录用户的基本信息
     * @var array
     */
    public $user = null;
    public $miniInfo = null;
    public $headers = [];
    public $simulationLogin = false; // 是否账号模拟登陆

    protected function _initialize()
    {
        parent::_initialize();
        // 该接口是否可以免登陆
        $isExemptLogin = $this->getIsExemptLogin(); // true可以免登陆 false必须登陆

        if (!$this->isLogin() && !$isExemptLogin)
        {
            throw new ApiException('登录失效', 200, config('code.denied'));
        }

        $headers = request()->header();
        $this->headers = array_merge($headers, $this->headers);
    }

    /**
     * @return bool-
     * @throws ApiException
     */
    public function isLogin()
    {
        if (!isset($this->headers['access-token']) || empty($this->headers['access-token'])) return false;
        // access-token AES解密
        $accessUserToken = $this->decryptWithOpenssl($this->headers['access-token']);

        if (empty($accessUserToken)) return false;

        if (!preg_match('/||/', $accessUserToken)) return false;

        [$token, $miniId] = explode('||', $accessUserToken);

        $miniInfo = (new MiniAppUser())->getMiniAppInfo($miniId);

        if ($miniInfo['access_token'] !== $token || $this->request->time() > $miniInfo['expires_in'] || $miniInfo['status'] != 0)
        {   // 判断token是否过期 并且账户状态正常
            return false;
        }
        $this->miniInfo = $miniInfo;

        $id = (int)($miniInfo['uid']);
        if (!$id)
        {
            $model = $this->request->module();
            $controller = $this->request->controller();
            $startNum = strpos($controller, '.');
            if ($startNum !== false)
            {
                $controller = substr($controller, $startNum + 1);
            }
            $action = $this->request->action(); // 全小写

            $uri = $model . '.' . $controller . '.' . $action;
            $noCheckUri = [

            ];  // 免绑手机号接口
            if (in_array($uri, $noCheckUri, true))
            {
                return true;
            } else
            {
                throw new ApiException('手机号未绑定', 200, 407);
            }
        }
        // 账号模拟
        $simulation = config('app.simulation');

        if ($id !== $simulation['from'])
        {
            $map['id'] = $id;
        } else
        {
            $map['id'] = $simulation['to'] ?: $id;
            if ($map['id'] === $simulation['to'])
            {   // 模拟登陆
                $this->simulationLogin = true;
            }
        }

        $userinfo = (new User())->getUserinfo($map);

        if (!$userinfo || empty($userinfo) || $userinfo['forbidden'] == 1) return false;

        $this->user = $userinfo;
        /**
         * 定义全局常量 UID 方便日志打印带上用户ID信息
         */
        if (!defined('USERINFO_UID'))
        {
            define('USERINFO_UID', $userinfo['id']);
        }

        return true;
    }

    /**
     * 判断本次请求是否免登陆
     *
     */
    public function getIsExemptLogin()
    {
        $model = $this->request->module();
        $controller = $this->request->controller();
        $startNum = strpos($controller, '.');
        if ($startNum !== false)
        {
            $controller = substr($controller, $startNum + 1);
        }
        $action = $this->request->action(); // 全小写

        $uri = $model . '.' . $controller . '.' . $action;

        $exemptLoginUri = [
            'miniweb.AstroExplain.index',//本命报告接口，h5可以免登陆看
        ];

        if (in_array($uri, $exemptLoginUri, true))
        {
            return true;
        }
        return false;
    }

    /**
     * 加密字符串
     * @param string $data 字符串
     * @return string
     */
    protected function encryptWithOpenssl($data): string
    {
        $config = config('miniapp');
        return base64_encode(openssl_encrypt($data, $config['aes_method'], $config['aes_key'], OPENSSL_RAW_DATA, $config['aes_iv']));
    }

    /**
     * 解密字符串
     * @param string $data 字符串
     * @return string
     */
    protected function decryptWithOpenssl($data): string
    {
        $config = config('miniapp');
        return openssl_decrypt(base64_decode($data), $config['aes_method'], $config['aes_key'], OPENSSL_RAW_DATA, $config['aes_iv']);
    }
}
